/* Copyright 2009 Requirements Management System 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.mags.remas.view;

import java.math.BigDecimal; 
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.validator.GenericValidator;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.IEditorInput;
import org.mags.common.EngineContext;
import org.mags.object.common.ParserFormatterUtils;
import org.mags.remas.control.EntityEditorInput;
import org.mags.remas.control.EntityRelationshipController;
import org.mags.remas.control.ListValueController;
import org.mags.remas.control.commons.Cloner;
import org.mags.remas.control.commons.ControlUtils;
import org.mags.remas.control.commons.CrudAction;
import org.mags.remas.exception.SingletonExceptionHandler;
import org.mags.remas.model.entity.EntityCategory;
import org.mags.remas.model.entity.EntityRelationship;
import org.mags.remas.model.entity.EntityStructure;
import org.mags.remas.model.entity.EnumValue;
import org.mags.remas.model.entity.KeyDefinition;
import org.mags.remas.model.entity.KeyValue;
import org.mags.remas.model.entity.provider.KeyTypeProvider;
import org.mags.remas.view.commons.ImageProvider;
import org.mags.remas.view.dialogs.RelationshipTreeDialog;
import org.mags.remas.view.dialogs.SingletonRelationshipTreeDialog;
import org.mags.remas.view.widgets.ListValueViewer;

/**
 * 
 * @author Mario Gaitan
 *
 */
public class EntityEditor extends AbstractEntityEditor {
	public static final String ID = "org.mags.remas.view.entityEditor";
	private List<KeyValue> keyValues;	
	private EntityRelationshipController viewController;	
	private CrudAction action;
	private EntityRelationship parentEntityRelationship;
	public EntityEditor() {
		super();
	}
	public EntityRelationshipController getViewController() {
		return viewController;
	}
	public void setViewController(EntityRelationshipController viewController) {
		this.viewController = viewController;
	}
	private void loadLinkAction() {
		final EntityStructure entityStructure = EngineContext.getDataContext().getEntityProviderFactory().getEntityStructureProvider().getById(entityRelationship.getEntity().getEntityType().getEntityTypeId(), entityRelationship.getEntityParent().getEntityType().getEntityTypeId());
		if(entityStructure.getLinkStructures().size()>0) {
			if(entityRelationship.getLink()!=null) {
				getLinkButton().setText(entityRelationship.getLink().getEntity().getCode());
				getLblLink().setText(entityRelationship.getLink().getEntity().getName());
				getLinkButton().setImage(ImageProvider.getEntityImage(entityRelationship.getLink().getEntity().getEntityType().getCode().toLowerCase()+".png"));					
			}
			else {
				getLinkButton().setText("[link]");
				getLblLink().setText("");
				getLinkButton().setImage(ImageProvider.getEntityImage("link.png"));				
			}
			getLinkButton().setEnabled(true);						
		} else
			getLinkButton().setEnabled(false);
	}
	public void loadCacheObject() {
		if(action==CrudAction.UPDATE) {
			try {
				entityRelationship = Cloner.clone(entityRelationship);
				entityRelationship.setEntity(Cloner.clone(entityRelationship.getEntity()));
			} catch(Exception e) {
				exceptionCatched(e);
			}
		}
	}
	@Override
	public void init(IEditorInput input) {
		action = ((EntityEditorInput)input).getAction();
		parentEntityRelationship = ((EntityEditorInput)input).getParentEntityRelationship();
		loadCacheObject();
	}
	@Override
	public void createPartControl(Composite parent) {
		super.createPartControl(parent);
		if(action==CrudAction.UPDATE) 
			fillControls();
		else if(action==CrudAction.CREATE) 
			super.getTxtName().setText(entityRelationship.getEntity().getEntityType().getName());
		loadLinkAction();
	}	
	public void fillAuditControls() {
		getFieldsControl().setToReadText("property_code", entityRelationship.getEntity().getCode());
		getFieldsControl().setToReadText("audit_createdby", entityRelationship.getEntity().getCreatedBy());
		getFieldsControl().setToReadText("audit_updatedby", entityRelationship.getEntity().getUpdatedBy());
		getFieldsControl().setToReadText("audit_creationdate", ParserFormatterUtils.getInstance().date2Text(entityRelationship.getEntity().getCreationDate()));
		getFieldsControl().setToReadText("audit_changedate", ParserFormatterUtils.getInstance().date2Text(entityRelationship.getEntity().getChangeDate()));		
	}
	@SuppressWarnings("unchecked")
	public void fillControls() {
		getFieldsControl().setToText("property_name", entityRelationship.getEntity().getName());
		getFieldsControl().setToText("property_description", entityRelationship.getEntity().getDescription());
		fillAuditControls();
		KeyTypeProvider keyTypeProvider = EngineContext.getDataContext().getEntityProviderFactory().getKeyTypeProvider();
		keyValues = EngineContext.getDataContext().getEntityProviderFactory().getKeyValueProvider().getByEntityId(entityRelationship.getEntity().getEntityId());
		for(KeyValue value: keyValues) {
			if(keyTypeProvider.isENUM(value.getKeyDefinition().getKeyType())) {
				List<EnumValue> enumValues = (List<EnumValue>)getFieldsControl().getComboList("propertyidx_"+value.getKeyDefinition().getName());
				if(value.getEnumValue()!=null)
					for(EnumValue enumValue: enumValues) 
						if(enumValue.getEnumValueId()==value.getEnumValue().getEnumValueId()) {
							value.setEnumValue(enumValue);
							break;
						}
				getFieldsControl().setToCombo("propertyidx_"+value.getKeyDefinition().getName(), value.getEnumValue());
			} else if(keyTypeProvider.isLIST(value.getKeyDefinition().getKeyType())) {
				/*DO NOTHING*/
			} else {
				if(keyTypeProvider.isDATE(value.getKeyDefinition().getKeyType()))
					getFieldsControl().setToTextDate("propertyidx_"+value.getKeyDefinition().getName(), value.getDateValue());
				else if(keyTypeProvider.isINTEGER(value.getKeyDefinition().getKeyType())) {
					String integerValue = "0";
					if(value.getNumericValue()!=null) {
						NumberFormat formatter = new DecimalFormat("##");
						integerValue = formatter.format(value.getNumericValue().doubleValue());
					}
					getFieldsControl().setToText("propertyidx_"+value.getKeyDefinition().getName(), integerValue);
				}
				else if(keyTypeProvider.isFLOAT(value.getKeyDefinition().getKeyType())) {
					String floatValue = "0";
					if(value.getNumericValue()!=null) {
						NumberFormat formatter = new DecimalFormat();
						floatValue = formatter.format(value.getNumericValue().doubleValue());
					}
					getFieldsControl().setToText("propertyidx_"+value.getKeyDefinition().getName(), floatValue);
				}				
				else if(keyTypeProvider.isVARCHAR(value.getKeyDefinition().getKeyType()))
					getFieldsControl().setToText("propertyidx_"+value.getKeyDefinition().getName(), value.getVarcharValue());
			}
		}		
	}
	private void fillElement() {
		entityRelationship.getEntity().setName(getFieldsControl().getFromText("property_name"));
		entityRelationship.getEntity().setDescription(getFieldsControl().getFromText("property_description"));		
		KeyTypeProvider keyTypeProvider = EngineContext.getDataContext().getEntityProviderFactory().getKeyTypeProvider();
		Set<String> keyNames = getFieldsControl().getControls().keySet();
		KeyValue value=null;
		for(String keyName: keyNames) {
			if(keyName.startsWith("propertyidx_")) {
				KeyDefinition keyDefinition = (KeyDefinition)getFieldsControl().getControls().get(keyName).getData();
				value = null;
				if(action==CrudAction.UPDATE) {
					for(KeyValue v: keyValues)
						if(v.getKeyDefinition().getKeyDefinitionId()==keyDefinition.getKeyDefinitionId()) {
							value = v;
							break;
						}	
				} 
				if(value==null) {
					if(keyValues==null)
						keyValues = new ArrayList<KeyValue>();
					value = new KeyValue();
					value.setKeyDefinition(keyDefinition);
					keyValues.add(value);
				}
				value.setDateValue(null);
				value.setNumericValue(null);
				value.setVarcharValue(null);
				value.setEnumValue(null);
				if(keyTypeProvider.isENUM(keyDefinition.getKeyType())) 
					value.setEnumValue((EnumValue)getFieldsControl().getFromCombo(keyName));
				else if(keyTypeProvider.isLIST(keyDefinition.getKeyType())) {
					/*DO NOTHING*/
				}
				else {
					if(keyTypeProvider.isDATE(keyDefinition.getKeyType()))
						value.setDateValue(getFieldsControl().getFromTextDate(keyName));
					else if(keyTypeProvider.isINTEGER(keyDefinition.getKeyType())) {
						String strValue = getFieldsControl().getFromText(keyName);
						if(!strValue.equals(""))
							value.setNumericValue(new BigDecimal(ParserFormatterUtils.getInstance().parseInteger(strValue)));
					}
					else if(keyTypeProvider.isFLOAT(keyDefinition.getKeyType())) {
						String strValue = getFieldsControl().getFromText(keyName);
						if(!strValue.equals(""))
							value.setNumericValue(ParserFormatterUtils.getInstance().parseDecimal(strValue));
					}					
					else if(keyTypeProvider.isVARCHAR(keyDefinition.getKeyType())) 
						value.setVarcharValue(getFieldsControl().getFromText(keyName));
				}
				
			}	
		}
	}
	public boolean validateControls() {
		String message = "";
		EntityStructure entityStructure = EngineContext.getDataContext().getEntityProviderFactory().getEntityStructureProvider().getById(entityRelationship.getEntity().getEntityType().getEntityTypeId(), entityRelationship.getEntityParent().getEntityType().getEntityTypeId());
		if(entityStructure.getNullLink().equalsIgnoreCase("N")&&entityStructure.getLinkStructures().size()>0&&entityRelationship.getLink()==null) {
			if(!message.equals("")) message = message + ", ";
			message = message + "link is required";
		}
		if(GenericValidator.isBlankOrNull(getTxtName().getText())) {
			if(!message.equals("")) message = message + ", ";
			message = message + "name is required";
		}
		KeyTypeProvider keyTypeProvider = EngineContext.getDataContext().getEntityProviderFactory().getKeyTypeProvider();
		Set<String> keyNames = getFieldsControl().getControls().keySet();
		for(String keyName: keyNames) {
			if(keyName.startsWith("propertyidx_")) {
				KeyDefinition keyDefinition = (KeyDefinition)getFieldsControl().getControls().get(keyName).getData();
				if(keyTypeProvider.isENUM(keyDefinition.getKeyType())&&getFieldsControl().getFromCombo(keyName)==null&&keyDefinition.getAllowEmpty().equalsIgnoreCase("N")) {
					if(!message.equals("")) message = message + ", ";
					message = message + keyDefinition.getName()+ " is required";					
				} else if(keyTypeProvider.isLIST(keyDefinition.getKeyType())) {
					/*DO NOTHING*/
				}
				else {
					if(keyTypeProvider.isDATE(keyDefinition.getKeyType())&&getFieldsControl().getFromTextDate(keyName)==null&&keyDefinition.getAllowEmpty().equalsIgnoreCase("N")) {
						if(!message.equals("")) message = message + ", ";
						message = message + keyDefinition.getName()+ " is required";					
					}
					else if(keyTypeProvider.isINTEGER(keyDefinition.getKeyType())&&GenericValidator.isBlankOrNull(getFieldsControl().getFromText(keyName))&&keyDefinition.getAllowEmpty().equalsIgnoreCase("N")) {
						if(!message.equals("")) message = message + ", ";
						message = message + keyDefinition.getName()+ " is required";											
					}
					else if(keyTypeProvider.isFLOAT(keyDefinition.getKeyType())&&GenericValidator.isBlankOrNull(getFieldsControl().getFromText(keyName))&&keyDefinition.getAllowEmpty().equalsIgnoreCase("N")) {
						if(!message.equals("")) message = message + ", ";
						message = message + keyDefinition.getName()+ " is required";											
					}					
					else if(keyTypeProvider.isVARCHAR(keyDefinition.getKeyType())&&GenericValidator.isBlankOrNull(getFieldsControl().getFromText(keyName))&&keyDefinition.getAllowEmpty().equalsIgnoreCase("N")) {
						if(!message.equals("")) message = message + ", ";
						message = message + keyDefinition.getName()+ " is required";											
					}
				}
				
			}	
		}
		if(!message.equals(""))
			SingletonExceptionHandler.getInstance().showError(message);
		return message.equals("");
	}
	@SuppressWarnings("unchecked")
	@Override
	public void save() {
		if(entityRelationship==null)
			throw new RuntimeException("There isn't element to save");
		if(validateControls()) {
			fillElement();
			if(action==CrudAction.CREATE) {
				Map<String, Object> changes = viewController.create(entityRelationship, parentEntityRelationship, keyValues);
				this.entityRelationship = (EntityRelationship)changes.get("entityRelationship");
				this.keyValues = (List<KeyValue>)changes.get("keyValues");
				action=CrudAction.UPDATE;
			}
			else {
				Map<String, Object> changes = viewController.update(entityRelationship, keyValues);
				this.entityRelationship = (EntityRelationship)changes.get("entityRelationship");
				this.keyValues = (List<KeyValue>)changes.get("keyValues");				
			}
			if(super.getListViewers()!=null) {
				for(ListValueViewer viewer: super.getListViewers()) {
					ListValueController controller = (ListValueController)viewer.getCrudActions();
					controller.setEntityRelationship(this.entityRelationship);
				}
			}
			getFieldsControl().setToText("property_name", entityRelationship.getEntity().getName());
			getFieldsControl().setToText("property_description", entityRelationship.getEntity().getDescription());
		}
		fillAuditControls();
		super.save();
	}
	@Override
	public void cancel() {
		super.closeMe();
	}
	@Override
	public void selectLink() {
		if(entityRelationship==null)
			throw new RuntimeException("There isn't element to load a link");
		EntityStructure entityStructure = EngineContext.getDataContext().getEntityProviderFactory().getEntityStructureProvider().getById(entityRelationship.getEntity().getEntityType().getEntityTypeId(), entityRelationship.getEntityParent().getEntityType().getEntityTypeId());
		SingletonRelationshipTreeDialog treeDialog = SingletonRelationshipTreeDialog.getInstance(getSite().getShell().getDisplay());
		if(entityRelationship.getLink()!=null)
			treeDialog.setSelectedEntityRelationship(entityRelationship.getLink());
		else {
			EntityCategory entityCategory = ControlUtils.selectCategory(entityStructure);
			if(entityCategory!=null)
				treeDialog.setSelectedEntityCategory(entityCategory);			
		}
		String text = ControlUtils.makeSelectLabel(entityStructure);
		text = "select: "+text;
		treeDialog.setText(text);					
		treeDialog.show();
		if(treeDialog.getStatus()==RelationshipTreeDialog.STATUS_CANCELED)
			return;
		EntityRelationship selected = treeDialog.getSelectedEntityRelationship();
		if(entityStructure.getNullLink().equalsIgnoreCase("N")&&selected==null) {
			SingletonExceptionHandler.getInstance().showError("link can't be null");
			return ;
		}		
		entityRelationship.setLink(selected);
		loadLinkAction();
	}
	@Override
	public void refresh() {
		if(entityRelationship==null)
			throw new RuntimeException("There isn't element to refresh");
		if(action==CrudAction.UPDATE) {
			entityRelationship = viewController.refresh(entityRelationship);
			if(entityRelationship==null)
				throw new RuntimeException("Element was deleted little time ago");
			loadCacheObject();
			fillControls();
			loadLinkAction();
		}
	}
	@Override
	public boolean ignoreException(Exception e) {
		if(e instanceof org.eclipse.swt.SWTException && e.getMessage().equalsIgnoreCase("Widget is disposed")) {
			SingletonExceptionHandler.getInstance().showWarning(e);
			//viewController.setTreeViewListener(null);
			return true;
		}
		return false;
	}
}
